
#pragma once 

namespace SkeinOrg
{
    // #include "brg_types.h"                      /* get integer type definitions */

    /*
    ---------------------------------------------------------------------------
    Copyright (c) 1998-2006, Brian Gladman, Worcester, UK. All rights reserved.

    LICENSE TERMS

    The free distribution and use of this software in both source and binary
    form is allowed (with or without changes) provided that:

    1. distributions of this source code include the above copyright
    notice, this list of conditions and the following disclaimer;

    2. distributions in binary form include the above copyright
    notice, this list of conditions and the following disclaimer
    in the documentation and/or other associated materials;

    3. the copyright holder's name is not used to endorse products
    built using this software without specific written permission.

    ALTERNATIVELY, provided that this notice is retained in full, this product
    may be distributed under the terms of the GNU General Public License (GPL),
    in which case the provisions of the GPL apply INSTEAD OF those given above.

    DISCLAIMER

    This software is provided 'as is' with no explicit or implied warranties
    in respect of its properties, including, but not limited to, correctness
    and/or fitness for purpose.
    ---------------------------------------------------------------------------
    Issue 09/09/2006

    The unsigned integer types defined here are of the form uint_<nn>t where
    <nn> is the length of the type; for example, the unsigned 32-bit type is
    'uint_32t'.  These are NOT the same as the 'C99 integer types' that are
    defined in the inttypes.h and stdint.h headers since attempts to use these
    types have shown that support for them is still highly variable.  However,
    since the latter are of the form uint<nn>_t, a regular expression search
    and replace (in VC++ search on 'uint_{:z}t' and replace with 'uint\1_t')
    can be used to convert the types used here to the C99 standard types.
    */

    #ifndef BRG_TYPES_H
    #define BRG_TYPES_H

    #if defined(__cplusplus)
        extern "C" {
    #endif

    #ifndef BRG_UI8
    #  define BRG_UI8
    #  if UCHAR_MAX == 255u
            typedef unsigned char uint_8t;
    #  else
    #    error Please define uint_8t as an 8-bit unsigned integer type in brg_types.h
    #  endif
    #endif

    #ifndef BRG_UI16
    #  define BRG_UI16
    #  if USHRT_MAX == 65535u
            typedef unsigned short uint_16t;
    #  else
    #    error Please define uint_16t as a 16-bit unsigned short type in brg_types.h
    #  endif
    #endif

    #ifndef BRG_UI32
    #  define BRG_UI32
    #  if UINT_MAX == 4294967295u
    #    define li_32(h) 0x##h##u
            typedef unsigned int uint_32t;
    #  elif ULONG_MAX == 4294967295u
    #    define li_32(h) 0x##h##ul
            typedef unsigned long uint_32t;
    #  elif defined( _CRAY )
    #    error This code needs 32-bit data types, which Cray machines do not provide
    #  else
    #    error Please define uint_32t as a 32-bit unsigned integer type in brg_types.h
    #  endif
    #endif

    #ifndef BRG_UI64
    #  if defined( __BORLANDC__ ) && !defined( __MSDOS__ )
    #    define BRG_UI64
    #    define li_64(h) 0x##h##ui64
            typedef unsigned __int64 uint_64t;
    #  elif defined( _MSC_VER ) && ( _MSC_VER < 1300 )    /* 1300 == VC++ 7.0 */
    #    define BRG_UI64
    #    define li_64(h) 0x##h##ui64
            typedef unsigned __int64 uint_64t;
    #  elif defined( __sun ) && defined(ULONG_MAX) && ULONG_MAX == 0xfffffffful
    #    define BRG_UI64
    #    define li_64(h) 0x##h##ull
            typedef unsigned long long uint_64t;
    #  elif defined( UINT_MAX ) && UINT_MAX > 4294967295u
    #    if UINT_MAX == 18446744073709551615u
    #      define BRG_UI64
    #      define li_64(h) 0x##h##u
            typedef unsigned int uint_64t;
    #    endif
    #  elif defined( ULONG_MAX ) && ULONG_MAX > 4294967295u
    #    if ULONG_MAX == 18446744073709551615ul
    #      define BRG_UI64
    #      define li_64(h) 0x##h##ul
            typedef unsigned long uint_64t;
    #    endif
    #  elif defined( ULLONG_MAX ) && ULLONG_MAX > 4294967295u
    #    if ULLONG_MAX == 18446744073709551615ull
    #      define BRG_UI64
    #      define li_64(h) 0x##h##ull
            typedef unsigned long long uint_64t;
    #    endif
    #  elif defined( ULONG_LONG_MAX ) && ULONG_LONG_MAX > 4294967295u
    #    if ULONG_LONG_MAX == 18446744073709551615ull
    #      define BRG_UI64
    #      define li_64(h) 0x##h##ull
            typedef unsigned long long uint_64t;
    #    endif
    #  elif defined(__GNUC__)  /* DLW: avoid mingw problem with -ansi */
    #      define BRG_UI64
    #      define li_64(h) 0x##h##ull
            typedef unsigned long long uint_64t;
    #  endif
    #endif

    #if defined( NEED_UINT_64T ) && !defined( BRG_UI64 )
    #  error Please define uint_64t as an unsigned 64 bit type in brg_types.h
    #endif

    #ifndef RETURN_VALUES
    #  define RETURN_VALUES
    #  if defined( DLL_EXPORT )
    #    if defined( _MSC_VER ) || defined ( __INTEL_COMPILER )
    #      define VOID_RETURN    __declspec( dllexport ) void __stdcall
    #      define INT_RETURN     __declspec( dllexport ) int  __stdcall
    #    elif defined( __GNUC__ )
    #      define VOID_RETURN    __declspec( __dllexport__ ) void
    #      define INT_RETURN     __declspec( __dllexport__ ) int
    #    else
    #      error Use of the DLL is only available on the Microsoft, Intel and GCC compilers
    #    endif
    #  elif defined( DLL_IMPORT )
    #    if defined( _MSC_VER ) || defined ( __INTEL_COMPILER )
    #      define VOID_RETURN    __declspec( dllimport ) void __stdcall
    #      define INT_RETURN     __declspec( dllimport ) int  __stdcall
    #    elif defined( __GNUC__ )
    #      define VOID_RETURN    __declspec( __dllimport__ ) void
    #      define INT_RETURN     __declspec( __dllimport__ ) int
    #    else
    #      error Use of the DLL is only available on the Microsoft, Intel and GCC compilers
    #    endif
    #  elif defined( __WATCOMC__ )
    #    define VOID_RETURN  void __cdecl
    #    define INT_RETURN   int  __cdecl
    #  else
    #    define VOID_RETURN  void
    #    define INT_RETURN   int
    #  endif
    #endif

        /*  These defines are used to declare buffers in a way that allows
        faster operations on longer variables to be used.  In all these
        defines 'size' must be a power of 2 and >= 8

        dec_unit_type(size,x)       declares a variable 'x' of length
        'size' bits

        dec_bufr_type(size,bsize,x) declares a buffer 'x' of length 'bsize'
        bytes defined as an array of variables
        each of 'size' bits (bsize must be a
        multiple of size / 8)

        ptr_cast(x,size)            casts a pointer to a pointer to a
        varaiable of length 'size' bits
        */

    #define ui_type(size)               uint_##size##t
    #define dec_unit_type(size,x)       typedef ui_type(size) x
    #define dec_bufr_type(size,bsize,x) typedef ui_type(size) x[bsize / (size >> 3)]
    #define ptr_cast(x,size)            ((ui_type(size)*)(x))

    #if defined(__cplusplus)
        }
    #endif

    #endif

    // #include "skein_port.h"                      /* get platform-specific definitions */

    /*******************************************************************
    **
    ** Platform-specific definitions for Skein hash function.
    **
    ** Source code author: Doug Whiting, 2008.
    **
    ** This algorithm and source code is released to the public domain.
    **
    ** Many thanks to Brian Gladman for his portable header files.
    **
    ** To port Skein to an "unsupported" platform, change the definitions
    ** in this file appropriately.
    **
    ********************************************************************/

    typedef unsigned int    uint_t;             /* native unsigned integer */
    typedef uint_8t         u08b_t;             /*  8-bit unsigned integer */
    typedef uint_64t        u64b_t;             /* 64-bit unsigned integer */

    #ifndef RotL_64
    #define RotL_64(x,N)    (((x) << (N)) | ((x) >> (64-(N))))
    #endif

    /*
    * Skein is "natively" little-endian (unlike SHA-xxx), for optimal
    * performance on x86 CPUs.  The Skein code requires the following
    * definitions for dealing with endianness:
    *
    *    SKEIN_NEED_SWAP:  0 for little-endian, 1 for big-endian
    *    Skein_Put64_LSB_First
    *    Skein_Get64_LSB_First
    *    Skein_Swap64
    *
    * If SKEIN_NEED_SWAP is defined at compile time, it is used here
    * along with the portable versions of Put64/Get64/Swap64, which
    * are slow in general.
    *
    * Otherwise, an "auto-detect" of endianness is attempted below.
    * If the default handling doesn't work well, the user may insert
    * platform-specific code instead (e.g., for big-endian CPUs).
    *
    */
    #ifndef SKEIN_NEED_SWAP /* compile-time "override" for endianness? */

    //#include "brg_endian.h"                     /* get endianness selection */
    /*
    ---------------------------------------------------------------------------
    Copyright (c) 2003, Dr Brian Gladman, Worcester, UK.   All rights reserved.

    LICENSE TERMS

    The free distribution and use of this software in both source and binary
    form is allowed (with or without changes) provided that:

    1. distributions of this source code include the above copyright
    notice, this list of conditions and the following disclaimer;

    2. distributions in binary form include the above copyright
    notice, this list of conditions and the following disclaimer
    in the documentation and/or other associated materials;

    3. the copyright holder's name is not used to endorse products
    built using this software without specific written permission.

    ALTERNATIVELY, provided that this notice is retained in full, this product
    may be distributed under the terms of the GNU General Public License (GPL),
    in which case the provisions of the GPL apply INSTEAD OF those given above.

    DISCLAIMER

    This software is provided 'as is' with no explicit or implied warranties
    in respect of its properties, including, but not limited to, correctness
    and/or fitness for purpose.
    ---------------------------------------------------------------------------
    Issue 20/10/2006
    */

    #define IS_BIG_ENDIAN      4321 /* byte 0 is most significant (mc68k) */
    #define IS_LITTLE_ENDIAN   1234 /* byte 0 is least significant (i386) */

        /* Include files where endian defines and byteswap functions may reside */
    #if defined( __FreeBSD__ ) || defined( __OpenBSD__ ) || defined( __NetBSD__ )
    #  include <sys/endian.h>
    #elif defined( BSD ) && ( BSD >= 199103 ) || defined( __APPLE__ ) || \
        defined(__CYGWIN32__) || defined(__DJGPP__) || defined(__osf__)
    #  include <machine/endian.h>
    #elif defined( __linux__ ) || defined( __GNUC__ ) || defined( __GNU_LIBRARY__ )
    #  if !defined( __MINGW32__ ) && !defined(AVR)
    #    include <endian.h>
    #    if !defined( __BEOS__ )
    #      include <byteswap.h>
    #    endif
    #  endif
    #endif

    /* Now attempt to set the define for platform byte order using any  */
    /* of the four forms SYMBOL, _SYMBOL, __SYMBOL & __SYMBOL__, which  */
    /* seem to encompass most endian symbol definitions                 */

    #if defined( BIG_ENDIAN ) && defined( LITTLE_ENDIAN )
    #  if defined( BYTE_ORDER ) && BYTE_ORDER == BIG_ENDIAN
    #    define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
    #  elif defined( BYTE_ORDER ) && BYTE_ORDER == LITTLE_ENDIAN
    #    define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
    #  endif
    #elif defined( BIG_ENDIAN )
    #  define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
    #elif defined( LITTLE_ENDIAN )
    #  define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
    #endif

    #if defined( _BIG_ENDIAN ) && defined( _LITTLE_ENDIAN )
    #  if defined( _BYTE_ORDER ) && _BYTE_ORDER == _BIG_ENDIAN
    #    define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
    #  elif defined( _BYTE_ORDER ) && _BYTE_ORDER == _LITTLE_ENDIAN
    #    define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
    #  endif
    #elif defined( _BIG_ENDIAN )
    #  define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
    #elif defined( _LITTLE_ENDIAN )
    #  define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
    #endif

    #if defined( __BIG_ENDIAN ) && defined( __LITTLE_ENDIAN )
    #  if defined( __BYTE_ORDER ) && __BYTE_ORDER == __BIG_ENDIAN
    #    define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
    #  elif defined( __BYTE_ORDER ) && __BYTE_ORDER == __LITTLE_ENDIAN
    #    define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
    #  endif
    #elif defined( __BIG_ENDIAN )
    #  define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
    #elif defined( __LITTLE_ENDIAN )
    #  define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
    #endif

    #if defined( __BIG_ENDIAN__ ) && defined( __LITTLE_ENDIAN__ )
    #  if defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __BIG_ENDIAN__
    #    define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
    #  elif defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __LITTLE_ENDIAN__
    #    define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
    #  endif
    #elif defined( __BIG_ENDIAN__ )
    #  define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
    #elif defined( __LITTLE_ENDIAN__ )
    #  define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
    #endif

        /*  if the platform byte order could not be determined, then try to */
        /*  set this define using common machine defines                    */
    #if !defined(PLATFORM_BYTE_ORDER)

    #if   defined( __alpha__ ) || defined( __alpha ) || defined( i386 )       || \
        defined(__i386__) || defined(_M_I86) || defined(_M_IX86) || \
        defined(__OS2__) || defined(sun386) || defined(__TURBOC__) || \
        defined(vax) || defined(vms) || defined(VMS) || \
        defined(__VMS) || defined(_M_X64) || defined(AVR)
    #  define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN

    #elif defined( AMIGA )   || defined( applec )    || defined( __AS400__ )  || \
        defined(_CRAY) || defined(__hppa) || defined(__hp9000) || \
        defined(ibm370) || defined(mc68000) || defined(m68k) || \
        defined(__MRC__) || defined(__MVS__) || defined(__MWERKS__) || \
        defined(sparc) || defined(__sparc) || defined(SYMANTEC_C) || \
        defined(__VOS__) || defined(__TIGCC__) || defined(__TANDEM) || \
        defined(THINK_C) || defined(__VMCMS__)
    #  define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN

    #elif 0     /* **** EDIT HERE IF NECESSARY **** */
    #  define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
    #elif 0     /* **** EDIT HERE IF NECESSARY **** */
    #  define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
    #else
    #  error Please edit lines 126 or 128 in brg_endian.h to set the platform byte order
    #endif
    #endif

        /* special handler for IA64, which may be either endianness (?)  */
        /* here we assume little-endian, but this may need to be changed */
    #if defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
    #  define PLATFORM_MUST_ALIGN (1)
    #ifndef PLATFORM_BYTE_ORDER
    #  define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
    #endif
    #endif

    #ifndef   PLATFORM_MUST_ALIGN
    #  define PLATFORM_MUST_ALIGN (0)
    #endif


    #if   PLATFORM_BYTE_ORDER == IS_BIG_ENDIAN
    /* here for big-endian CPUs */
    #define SKEIN_NEED_SWAP   (1)
    #elif PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN
        /* here for x86 and x86-64 CPUs (and other detected little-endian CPUs) */
    #define SKEIN_NEED_SWAP   (0)
    #if   PLATFORM_MUST_ALIGN == 0              /* ok to use "fast" versions? */
    #define Skein_Put64_LSB_First(dst08,src64,bCnt) memcpy(dst08,src64,bCnt)
    #define Skein_Get64_LSB_First(dst64,src08,wCnt) memcpy(dst64,src08,8*(wCnt))
    #endif
    #else
    #error "Skein needs endianness setting!"
    #endif

    #endif /* ifndef SKEIN_NEED_SWAP */

    /*
    ******************************************************************
    *      Provide any definitions still needed.
    ******************************************************************
    */
    #ifndef Skein_Swap64  /* swap for big-endian, nop for little-endian */
    #if     SKEIN_NEED_SWAP
    #define Skein_Swap64(w64)                       \
        (((((u64b_t)(w64)) & 0xFF) << 56) | \
        (((((u64b_t)(w64)) >> 8) & 0xFF) << 48) | \
        (((((u64b_t)(w64)) >> 16) & 0xFF) << 40) | \
        (((((u64b_t)(w64)) >> 24) & 0xFF) << 32) | \
        (((((u64b_t)(w64)) >> 32) & 0xFF) << 24) | \
        (((((u64b_t)(w64)) >> 40) & 0xFF) << 16) | \
        (((((u64b_t)(w64)) >> 48) & 0xFF) << 8) | \
        (((((u64b_t)(w64)) >> 56) & 0xFF)))
    #else
    #define Skein_Swap64(w64)  (w64)
    #endif
    #endif  /* ifndef Skein_Swap64 */


    #ifndef Skein_Put64_LSB_First
        void    Skein_Put64_LSB_First(u08b_t *dst, const u64b_t *src, size_t bCnt)
    #ifdef  SKEIN_PORT_CODE /* instantiate the function code here? */
        { /* this version is fully portable (big-endian or little-endian), but slow */
            size_t n;

            for (n = 0; n<bCnt; n++)
                dst[n] = (u08b_t)(src[n >> 3] >> (8 * (n & 7)));
        }
    #else
            ;    /* output only the function prototype */
    #endif
    #endif   /* ifndef Skein_Put64_LSB_First */


    #ifndef Skein_Get64_LSB_First
        void    Skein_Get64_LSB_First(u64b_t *dst, const u08b_t *src, size_t wCnt)
    #ifdef  SKEIN_PORT_CODE /* instantiate the function code here? */
        { /* this version is fully portable (big-endian or little-endian), but slow */
            size_t n;

            for (n = 0; n<8 * wCnt; n += 8)
                dst[n / 8] = (((u64b_t)src[n])) +
                (((u64b_t)src[n + 1]) << 8) +
                (((u64b_t)src[n + 2]) << 16) +
                (((u64b_t)src[n + 3]) << 24) +
                (((u64b_t)src[n + 4]) << 32) +
                (((u64b_t)src[n + 5]) << 40) +
                (((u64b_t)src[n + 6]) << 48) +
                (((u64b_t)src[n + 7]) << 56);
        }
    #else
            ;    /* output only the function prototype */
    #endif
#endif   /* ifndef Skein_Get64_LSB_First */

    // #include "skein.h"

    /**************************************************************************
    **
    ** Interface declarations and internal definitions for Skein hashing.
    **
    ** Source code author: Doug Whiting, 2008.
    **
    ** This algorithm and source code is released to the public domain.
    **
    ***************************************************************************
    **
    ** The following compile-time switches may be defined to control some
    ** tradeoffs between speed, code size, error checking, and security.
    **
    ** The "default" note explains what happens when the switch is not defined.
    **
    **  SKEIN_DEBUG            -- make callouts from inside Skein code
    **                            to examine/display intermediate values.
    **                            [default: no callouts (no overhead)]
    **
    **  SKEIN_ERR_CHECK        -- how error checking is handled inside Skein
    **                            code. If not defined, most error checking
    **                            is disabled (for performance). Otherwise,
    **                            the switch value is interpreted as:
    **                                0: use assert()      to flag errors
    **                                1: return SKEIN_FAIL to flag errors
    **
    ***************************************************************************/

    enum
    {
        SKEIN_SUCCESS = 0,          /* return codes from Skein calls */
        SKEIN_FAIL = 1,
        SKEIN_BAD_HASHLEN = 2
    };

    #define  SKEIN_MODIFIER_WORDS  ( 2)          /* number of modifier (tweak) words */

    #define  SKEIN_256_STATE_WORDS ( 4)
    #define  SKEIN_512_STATE_WORDS ( 8)
    #define  SKEIN1024_STATE_WORDS (16)
    #define  SKEIN_MAX_STATE_WORDS (16)

    #define  SKEIN_256_STATE_BYTES ( 8*SKEIN_256_STATE_WORDS)
    #define  SKEIN_512_STATE_BYTES ( 8*SKEIN_512_STATE_WORDS)
    #define  SKEIN1024_STATE_BYTES ( 8*SKEIN1024_STATE_WORDS)

    #define  SKEIN_256_STATE_BITS  (64*SKEIN_256_STATE_WORDS)
    #define  SKEIN_512_STATE_BITS  (64*SKEIN_512_STATE_WORDS)
    #define  SKEIN1024_STATE_BITS  (64*SKEIN1024_STATE_WORDS)

    #define  SKEIN_256_BLOCK_BYTES ( 8*SKEIN_256_STATE_WORDS)
    #define  SKEIN_512_BLOCK_BYTES ( 8*SKEIN_512_STATE_WORDS)
    #define  SKEIN1024_BLOCK_BYTES ( 8*SKEIN1024_STATE_WORDS)

    typedef struct
    {
        size_t  hashBitLen;                      /* size of hash result, in bits */
        size_t  bCnt;                            /* current byte count in buffer b[] */
        u64b_t  T[SKEIN_MODIFIER_WORDS];         /* tweak words: T[0]=byte cnt, T[1]=flags */
    } Skein_Ctxt_Hdr_t;

    typedef struct                               /*  256-bit Skein hash context structure */
    {
        Skein_Ctxt_Hdr_t h;                      /* common header context variables */
        u64b_t  X[SKEIN_256_STATE_WORDS];        /* chaining variables */
        u08b_t  b[SKEIN_256_BLOCK_BYTES];        /* partial block buffer (8-byte aligned) */
    } Skein_256_Ctxt_t;

    typedef struct                               /*  512-bit Skein hash context structure */
    {
        Skein_Ctxt_Hdr_t h;                      /* common header context variables */
        u64b_t  X[SKEIN_512_STATE_WORDS];        /* chaining variables */
        u08b_t  b[SKEIN_512_BLOCK_BYTES];        /* partial block buffer (8-byte aligned) */
    } Skein_512_Ctxt_t;

    typedef struct                               /* 1024-bit Skein hash context structure */
    {
        Skein_Ctxt_Hdr_t h;                      /* common header context variables */
        u64b_t  X[SKEIN1024_STATE_WORDS];        /* chaining variables */
        u08b_t  b[SKEIN1024_BLOCK_BYTES];        /* partial block buffer (8-byte aligned) */
    } Skein1024_Ctxt_t;

    /*   Skein APIs for (incremental) "straight hashing" */
    int  Skein_256_Init(Skein_256_Ctxt_t *ctx, size_t hashBitLen);
    int  Skein_512_Init(Skein_512_Ctxt_t *ctx, size_t hashBitLen);
    int  Skein1024_Init(Skein1024_Ctxt_t *ctx, size_t hashBitLen);

    int  Skein_256_Update(Skein_256_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt);
    int  Skein_512_Update(Skein_512_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt);
    int  Skein1024_Update(Skein1024_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt);

    int  Skein_256_Final(Skein_256_Ctxt_t *ctx, u08b_t * hashVal);
    int  Skein_512_Final(Skein_512_Ctxt_t *ctx, u08b_t * hashVal);
    int  Skein1024_Final(Skein1024_Ctxt_t *ctx, u08b_t * hashVal);

    /*
    **   Skein APIs for "extended" initialization: MAC keys, tree hashing.
    **   After an InitExt() call, just use Update/Final calls as with Init().
    **
    **   Notes: Same parameters as _Init() calls, plus treeInfo/key/keyBytes.
    **          When keyBytes == 0 and treeInfo == SKEIN_SEQUENTIAL,
    **              the results of InitExt() are identical to calling Init().
    **          The function Init() may be called once to "precompute" the IV for
    **              a given hashBitLen value, then by saving a copy of the context
    **              the IV computation may be avoided in later calls.
    **          Similarly, the function InitExt() may be called once per MAC key
    **              to precompute the MAC IV, then a copy of the context saved and
    **              reused for each new MAC computation.
    **/
    int  Skein_256_InitExt(Skein_256_Ctxt_t *ctx, size_t hashBitLen, u64b_t treeInfo, const u08b_t *key, size_t keyBytes);
    int  Skein_512_InitExt(Skein_512_Ctxt_t *ctx, size_t hashBitLen, u64b_t treeInfo, const u08b_t *key, size_t keyBytes);
    int  Skein1024_InitExt(Skein1024_Ctxt_t *ctx, size_t hashBitLen, u64b_t treeInfo, const u08b_t *key, size_t keyBytes);

    /*
    **   Skein APIs for MAC and tree hash:
    **      Final_Pad:  pad, do final block, but no OUTPUT type
    **      Output:     do just the output stage
    */
    int  Skein_256_Final_Pad(Skein_256_Ctxt_t *ctx, u08b_t * hashVal);
    int  Skein_512_Final_Pad(Skein_512_Ctxt_t *ctx, u08b_t * hashVal);
    int  Skein1024_Final_Pad(Skein1024_Ctxt_t *ctx, u08b_t * hashVal);

    #ifndef SKEIN_TREE_HASH
    #define SKEIN_TREE_HASH (1)
    #endif
    #if  SKEIN_TREE_HASH
        int  Skein_256_Output(Skein_256_Ctxt_t *ctx, u08b_t * hashVal);
        int  Skein_512_Output(Skein_512_Ctxt_t *ctx, u08b_t * hashVal);
        int  Skein1024_Output(Skein1024_Ctxt_t *ctx, u08b_t * hashVal);
    #endif

    /*****************************************************************
    ** "Internal" Skein definitions
    **    -- not needed for sequential hashing API, but will be
    **           helpful for other uses of Skein (e.g., tree hash mode).
    **    -- included here so that they can be shared between
    **           reference and optimized code.
    ******************************************************************/

    /* tweak word T[1]: bit field starting positions */
    #define SKEIN_T1_BIT(BIT)       ((BIT) - 64)            /* offset 64 because it's the second word  */

    #define SKEIN_T1_POS_TREE_LVL   SKEIN_T1_BIT(112)       /* bits 112..118: level in hash tree       */
    #define SKEIN_T1_POS_BIT_PAD    SKEIN_T1_BIT(119)       /* bit  119     : partial final input byte */
    #define SKEIN_T1_POS_BLK_TYPE   SKEIN_T1_BIT(120)       /* bits 120..125: type field               */
    #define SKEIN_T1_POS_FIRST      SKEIN_T1_BIT(126)       /* bits 126     : first block flag         */
    #define SKEIN_T1_POS_FINAL      SKEIN_T1_BIT(127)       /* bit  127     : final block flag         */

    /* tweak word T[1]: flag bit definition(s) */
    #define SKEIN_T1_FLAG_FIRST     (((u64b_t)  1 ) << SKEIN_T1_POS_FIRST)
    #define SKEIN_T1_FLAG_FINAL     (((u64b_t)  1 ) << SKEIN_T1_POS_FINAL)
    #define SKEIN_T1_FLAG_BIT_PAD   (((u64b_t)  1 ) << SKEIN_T1_POS_BIT_PAD)

    /* tweak word T[1]: tree level bit field mask */
    #define SKEIN_T1_TREE_LVL_MASK  (((u64b_t)0x7F) << SKEIN_T1_POS_TREE_LVL)
    #define SKEIN_T1_TREE_LEVEL(n)  (((u64b_t) (n)) << SKEIN_T1_POS_TREE_LVL)

    /* tweak word T[1]: block type field */
    #define SKEIN_BLK_TYPE_KEY      ( 0)                    /* key, for MAC and KDF */
    #define SKEIN_BLK_TYPE_CFG      ( 4)                    /* configuration block */
    #define SKEIN_BLK_TYPE_PERS     ( 8)                    /* personalization string */
    #define SKEIN_BLK_TYPE_PK       (12)                    /* public key (for digital signature hashing) */
    #define SKEIN_BLK_TYPE_KDF      (16)                    /* key identifier for KDF */
    #define SKEIN_BLK_TYPE_NONCE    (20)                    /* nonce for PRNG */
    #define SKEIN_BLK_TYPE_MSG      (48)                    /* message processing */
    #define SKEIN_BLK_TYPE_OUT      (63)                    /* output stage */
    #define SKEIN_BLK_TYPE_MASK     (63)                    /* bit field mask */

    #define SKEIN_T1_BLK_TYPE(T)   (((u64b_t) (SKEIN_BLK_TYPE_##T)) << SKEIN_T1_POS_BLK_TYPE)
    #define SKEIN_T1_BLK_TYPE_KEY   SKEIN_T1_BLK_TYPE(KEY)  /* key, for MAC and KDF */
    #define SKEIN_T1_BLK_TYPE_CFG   SKEIN_T1_BLK_TYPE(CFG)  /* configuration block */
    #define SKEIN_T1_BLK_TYPE_PERS  SKEIN_T1_BLK_TYPE(PERS) /* personalization string */
    #define SKEIN_T1_BLK_TYPE_PK    SKEIN_T1_BLK_TYPE(PK)   /* public key (for digital signature hashing) */
    #define SKEIN_T1_BLK_TYPE_KDF   SKEIN_T1_BLK_TYPE(KDF)  /* key identifier for KDF */
    #define SKEIN_T1_BLK_TYPE_NONCE SKEIN_T1_BLK_TYPE(NONCE)/* nonce for PRNG */
    #define SKEIN_T1_BLK_TYPE_MSG   SKEIN_T1_BLK_TYPE(MSG)  /* message processing */
    #define SKEIN_T1_BLK_TYPE_OUT   SKEIN_T1_BLK_TYPE(OUT)  /* output stage */
    #define SKEIN_T1_BLK_TYPE_MASK  SKEIN_T1_BLK_TYPE(MASK) /* field bit mask */

    #define SKEIN_T1_BLK_TYPE_CFG_FINAL       (SKEIN_T1_BLK_TYPE_CFG | SKEIN_T1_FLAG_FINAL)
    #define SKEIN_T1_BLK_TYPE_OUT_FINAL       (SKEIN_T1_BLK_TYPE_OUT | SKEIN_T1_FLAG_FINAL)

    #define SKEIN_VERSION           (1)

    #ifndef SKEIN_ID_STRING_LE      /* allow compile-time personalization */
    #define SKEIN_ID_STRING_LE      (0x33414853)            /* "SHA3" (little-endian)*/
    #endif

    #define SKEIN_MK_64(hi32,lo32)  ((lo32) + (((u64b_t) (hi32)) << 32))
    #define SKEIN_SCHEMA_VER        SKEIN_MK_64(SKEIN_VERSION,SKEIN_ID_STRING_LE)
    #define SKEIN_KS_PARITY         SKEIN_MK_64(0x55555555,0x55555555)

    #define SKEIN_CFG_STR_LEN       (4*8)

    /* bit field definitions in config block treeInfo word */
    #define SKEIN_CFG_TREE_LEAF_SIZE_POS  ( 0)
    #define SKEIN_CFG_TREE_NODE_SIZE_POS  ( 8)
    #define SKEIN_CFG_TREE_MAX_LEVEL_POS  (16)

    #define SKEIN_CFG_TREE_LEAF_SIZE_MSK  ((u64b_t) 0xFF) << SKEIN_CFG_TREE_LEAF_SIZE_POS)
    #define SKEIN_CFG_TREE_NODE_SIZE_MSK  ((u64b_t) 0xFF) << SKEIN_CFG_TREE_NODE_SIZE_POS)
    #define SKEIN_CFG_TREE_MAX_LEVEL_MSK  ((u64b_t) 0xFF) << SKEIN_CFG_TREE_MAX_LEVEL_POS)

    #define SKEIN_CFG_TREE_INFO_SEQUENTIAL (0) /* use as treeInfo in InitExt() call for sequential processing */
    #define SKEIN_CFG_TREE_INFO(leaf,node,maxLevel) ((u64b_t) ((leaf) | ((node) << 8) | ((maxLevel) << 16)))

    /*
    **   Skein macros for getting/setting tweak words, etc.
    **   These are useful for partial input bytes, hash tree init/update, etc.
    **/
    #define Skein_Get_Tweak(ctxPtr,TWK_NUM)         ((ctxPtr)->h.T[TWK_NUM])
    #define Skein_Set_Tweak(ctxPtr,TWK_NUM,tVal)    {(ctxPtr)->h.T[TWK_NUM] = (tVal);}

    #define Skein_Get_T0(ctxPtr)    Skein_Get_Tweak(ctxPtr,0)
    #define Skein_Get_T1(ctxPtr)    Skein_Get_Tweak(ctxPtr,1)
    #define Skein_Set_T0(ctxPtr,T0) Skein_Set_Tweak(ctxPtr,0,T0)
    #define Skein_Set_T1(ctxPtr,T1) Skein_Set_Tweak(ctxPtr,1,T1)

    /* set both tweak words at once */
    #define Skein_Set_T0_T1(ctxPtr,T0,T1)           \
        {                                           \
        Skein_Set_T0(ctxPtr, (T0));                  \
        Skein_Set_T1(ctxPtr, (T1));                  \
        }

    #define Skein_Set_Type(ctxPtr,BLK_TYPE)         \
        Skein_Set_T1(ctxPtr, SKEIN_T1_BLK_TYPE_##BLK_TYPE)

    /* set up for starting with a new type: h.T[0]=0; h.T[1] = NEW_TYPE; h.bCnt=0; */
    #define Skein_Start_New_Type(ctxPtr,BLK_TYPE)   \
        { \
        Skein_Set_T0_T1(ctxPtr, 0, SKEIN_T1_FLAG_FIRST | SKEIN_T1_BLK_TYPE_##BLK_TYPE);  \
        (ctxPtr)->h.bCnt = 0; \
        }

    #define Skein_Clear_First_Flag(hdr)      { (hdr).T[1] &= ~SKEIN_T1_FLAG_FIRST;       }
    #define Skein_Set_Bit_Pad_Flag(hdr)      { (hdr).T[1] |=  SKEIN_T1_FLAG_BIT_PAD;     }

    #define Skein_Set_Tree_Level(hdr,height) { (hdr).T[1] |= SKEIN_T1_TREE_LEVEL(height);}

    /*****************************************************************
    ** "Internal" Skein definitions for debugging and error checking
    ******************************************************************/
    #ifdef  SKEIN_DEBUG             /* examine/display intermediate values? */
    #include "skein_debug.h"
    #else                           /* default is no callouts */
    #define Skein_Show_Block(bits,ctx,X,blkPtr,wPtr,ksEvenPtr,ksOddPtr)
    #define Skein_Show_Round(bits,ctx,r,X)
    #define Skein_Show_R_Ptr(bits,ctx,r,X_ptr)
    #define Skein_Show_Final(bits,ctx,cnt,outPtr)
    #define Skein_Show_Key(bits,ctx,key,keyBytes)
    #endif

    #ifndef SKEIN_ERR_CHECK        /* run-time checks (e.g., bad params, uninitialized context)? */
    #define Skein_Assert(x,retCode)/* default: ignore all Asserts, for performance */
    #define Skein_assert(x)
    #elif   defined(SKEIN_ASSERT)
    #include <assert.h>     
    #define Skein_Assert(x,retCode) assert(x) 
    #define Skein_assert(x)         assert(x) 
    #else
    #include <assert.h>     
    #define Skein_Assert(x,retCode) { if (!(x)) return retCode; } /*  caller  error */
    #define Skein_assert(x)         assert(x)                     /* internal error */
    #endif

    /*****************************************************************
    ** Skein block function constants (shared across Ref and Opt code)
    ******************************************************************/
    enum
    {
        /* Skein_256 round rotation constants */
        R_256_0_0 = 5, R_256_0_1 = 56,
        R_256_1_0 = 36, R_256_1_1 = 28,
        R_256_2_0 = 13, R_256_2_1 = 46,
        R_256_3_0 = 58, R_256_3_1 = 44,
        R_256_4_0 = 26, R_256_4_1 = 20,
        R_256_5_0 = 53, R_256_5_1 = 35,
        R_256_6_0 = 11, R_256_6_1 = 42,
        R_256_7_0 = 59, R_256_7_1 = 50,

        /* Skein_512 round rotation constants */
        R_512_0_0 = 38, R_512_0_1 = 30, R_512_0_2 = 50, R_512_0_3 = 53,
        R_512_1_0 = 48, R_512_1_1 = 20, R_512_1_2 = 43, R_512_1_3 = 31,
        R_512_2_0 = 34, R_512_2_1 = 14, R_512_2_2 = 15, R_512_2_3 = 27,
        R_512_3_0 = 26, R_512_3_1 = 12, R_512_3_2 = 58, R_512_3_3 = 7,
        R_512_4_0 = 33, R_512_4_1 = 49, R_512_4_2 = 8, R_512_4_3 = 42,
        R_512_5_0 = 39, R_512_5_1 = 27, R_512_5_2 = 41, R_512_5_3 = 14,
        R_512_6_0 = 29, R_512_6_1 = 26, R_512_6_2 = 11, R_512_6_3 = 9,
        R_512_7_0 = 33, R_512_7_1 = 51, R_512_7_2 = 39, R_512_7_3 = 35,

        /* Skein1024 round rotation constants */
        R1024_0_0 = 55, R1024_0_1 = 43, R1024_0_2 = 37, R1024_0_3 = 40, R1024_0_4 = 16, R1024_0_5 = 22, R1024_0_6 = 38, R1024_0_7 = 12,
        R1024_1_0 = 25, R1024_1_1 = 25, R1024_1_2 = 46, R1024_1_3 = 13, R1024_1_4 = 14, R1024_1_5 = 13, R1024_1_6 = 52, R1024_1_7 = 57,
        R1024_2_0 = 33, R1024_2_1 = 8, R1024_2_2 = 18, R1024_2_3 = 57, R1024_2_4 = 21, R1024_2_5 = 12, R1024_2_6 = 32, R1024_2_7 = 54,
        R1024_3_0 = 34, R1024_3_1 = 43, R1024_3_2 = 25, R1024_3_3 = 60, R1024_3_4 = 44, R1024_3_5 = 9, R1024_3_6 = 59, R1024_3_7 = 34,
        R1024_4_0 = 28, R1024_4_1 = 7, R1024_4_2 = 47, R1024_4_3 = 48, R1024_4_4 = 51, R1024_4_5 = 9, R1024_4_6 = 35, R1024_4_7 = 41,
        R1024_5_0 = 17, R1024_5_1 = 6, R1024_5_2 = 18, R1024_5_3 = 25, R1024_5_4 = 43, R1024_5_5 = 42, R1024_5_6 = 40, R1024_5_7 = 15,
        R1024_6_0 = 58, R1024_6_1 = 7, R1024_6_2 = 32, R1024_6_3 = 45, R1024_6_4 = 19, R1024_6_5 = 18, R1024_6_6 = 2, R1024_6_7 = 56,
        R1024_7_0 = 47, R1024_7_1 = 49, R1024_7_2 = 27, R1024_7_3 = 58, R1024_7_4 = 37, R1024_7_5 = 48, R1024_7_6 = 53, R1024_7_7 = 56
    };

    #ifndef SKEIN_ROUNDS
    #define SKEIN_256_ROUNDS_TOTAL (72)          /* number of rounds for the different block sizes */
    #define SKEIN_512_ROUNDS_TOTAL (72)
    #define SKEIN1024_ROUNDS_TOTAL (80)
    #else                                        /* allow command-line define in range 8*(5..14)   */
    #define SKEIN_256_ROUNDS_TOTAL (8*((((SKEIN_ROUNDS/100) + 5) % 10) + 5))
    #define SKEIN_512_ROUNDS_TOTAL (8*((((SKEIN_ROUNDS/ 10) + 5) % 10) + 5))
    #define SKEIN1024_ROUNDS_TOTAL (8*((((SKEIN_ROUNDS    ) + 5) % 10) + 5))
    #endif

    /***********************************************************************
    **
    ** Interface declarations of the AHS API using the Skein hash function.
    **
    ** Source code author: Doug Whiting, 2008.
    **
    ** This algorithm and source code is released to the public domain.
    **
    ************************************************************************/

    typedef enum
    {
        SUCCESS = SKEIN_SUCCESS,
        FAIL = SKEIN_FAIL,
        BAD_HASHLEN = SKEIN_BAD_HASHLEN
    }
    HashReturn;

    typedef size_t   DataLength;                /* bit count  type */
    typedef u08b_t   BitSequence;               /* bit stream type */

    typedef struct
    {
        uint_t  statebits;                      /* 256, 512, or 1024 */
        union
        {
            Skein_Ctxt_Hdr_t h;                 /* common header "overlay" */
            Skein_256_Ctxt_t ctx_256;
            Skein_512_Ctxt_t ctx_512;
            Skein1024_Ctxt_t ctx1024;
        } u;
    }
    hashState;

    /* "incremental" hashing API */
    HashReturn Init(hashState *state, int hashbitlen);
    HashReturn Update(hashState *state, const BitSequence *data, DataLength databitlen);
    HashReturn Final(hashState *state, BitSequence *hashval);

    /* "all-in-one" call */
    HashReturn Hash(int hashbitlen, const BitSequence *data,
        DataLength databitlen, BitSequence *hashval);


    /*
    ** Re-define the compile-time constants below to change the selection
    ** of the Skein state size in the Init() function in SHA3api_ref.c.
    **
    ** That is, the NIST API does not allow for explicit selection of the
    ** Skein block size, so it must be done implicitly in the Init() function.
    ** The selection is controlled by these constants.
    */
    #ifndef SKEIN_256_NIST_MAX_HASHBITS
    #define SKEIN_256_NIST_MAX_HASHBITS (256)
    #endif

    #ifndef SKEIN_512_NIST_MAX_HASHBITS
    #define SKEIN_512_NIST_MAX_HASHBITS (512)
    #endif

}